package com.tn.auth.interceptor;

import com.tn.auth.annotation.WithToken;
import com.tn.auth.utils.TokenUtil;
import com.tn.auth.vo.TokenVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 认证信息校验拦截器
 *
 * @program: tn_aucy_java
 * @author: yangjiayao
 * @create: 2021/12/22
 */
@Slf4j
@Component
public class TokenInterceptor implements HandlerInterceptor {
    /**
     * token校验是否开启
     */
    @Value("${auth.tokenOn:false}")
    private boolean tokenOn;

    /**
     * 超时时长
     */
    @Value("${auth.expire:3600000}")
    private int expire;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws IOException {
        if (handler instanceof HandlerMethod) {
            if (hasPermission(request, (HandlerMethod) handler)) {
                return true;
            }
        }
        response.sendError(HttpStatus.FORBIDDEN.value(), "登录超时，请重新登录!");
        return false;
    }

    /**
     * 校验token
     *
     * @param request 请求
     * @param handler handler
     * @return 校验结果
     */
    private boolean hasPermission(HttpServletRequest request, HandlerMethod handler) {
        // token校验未开启时不进行校验
        if (!tokenOn) {
            return true;
        }
        // 获取注解
        WithToken annotation = handler.getMethodAnnotation(WithToken.class);
        if (unwantedToken(annotation)) {
            return true;
        }
        // 获取token
        String user = request.getHeader(TokenUtil.USER_PARAM_NAME);
        String loginToken = request.getHeader(TokenUtil.TOKEN_PARAM_NAME);
        if (null == user || null == loginToken) {
            log.warn("User {} check token failed: Missing token!", user);
            return false;
        }
        // 校验token
        TokenVO token = TokenUtil.tokenList.get(user);
        if (null == token) {
            log.warn("User {} check token failed: Not logged in!", user);
            return false;
        }
        if (System.currentTimeMillis() > token.getGrantTime() + getExpire(annotation)) {
            TokenUtil.tokenList.remove(user);
            log.info("User {} check token failed: Login timeout!", user);
            return false;
        }
        if (loginToken.equals(token.getToken())) {
            token.setGrantTime(System.currentTimeMillis());
            return true;
        } else {
            log.warn("User {} check token failed: invalid token!", user);
            return false;
        }
    }

    /**
     * 是否需要拦截
     *
     * @param annotation 注解
     * @return 是否需要拦截
     */
    private boolean unwantedToken(WithToken annotation) {
        return null != annotation && !annotation.require();
    }

    /**
     * 超期时间
     *
     * @param annotation 注解
     * @return 超期时间
     */
    private int getExpire(WithToken annotation) {
        return null == annotation ? expire : annotation.expire();
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                Exception ex) {
    }
}
